package com.young.quartz.service.impl;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.young.quartz.domain.dto.AddJobDto;
import com.young.quartz.domain.dto.JobOpertationDto;
import com.young.quartz.domain.dto.JobSearchDto;
import com.young.quartz.domain.vo.CommonResponse;
import com.young.quartz.domain.vo.JobInfo;
import com.young.quartz.mapper.JobInfoMapper;
import com.young.quartz.scheduler.BaseJob;
import com.young.quartz.service.JobService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class JobServiceImpl implements JobService {
    //加入Qulifier注解，通过名称注入bean
    @Autowired
    @Qualifier("Scheduler")
    private Scheduler scheduler;

    @Autowired
    private JobInfoMapper jobInfoMapper;

    @Override
    public CommonResponse addJob(AddJobDto addJobDto) throws Exception {
        String jobClassName = addJobDto.getJobClassName();
        Map<String, Object> resultMap = verifyClass(jobClassName);
        if (!(boolean) resultMap.get("result")){
            return CommonResponse.error(resultMap.get("message").toString());
        }
        String jobGroupName = addJobDto.getJobGroupName();
        String cronExpression = addJobDto.getCronExpression();
        // 启动调度器
        scheduler.start();
        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass())
                .withIdentity(addJobDto.getJobName(), jobGroupName).withDescription(addJobDto.getDescription()).build();
        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
                .withSchedule(scheduleBuilder).build();
        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            System.out.println("创建定时任务失败" + e);
            throw new Exception("创建定时任务失败");
        }
        return CommonResponse.success();
    }

    /**
     * 获取任务列表
     * @return
     */
    public Map<String,Object> getJobInfoList(JobSearchDto jobSearchDto) {
        Page<JobInfo> page = new Page<>(jobSearchDto.getPageNum(),jobSearchDto.getPageSize());
        // 不进行 count sql 优化，解决 MP 无法自动优化 SQL 问题，这时候你需要自己查询 count 部分
        // page.setOptimizeCountSql(false);
        // 当 total 为小于 0 或者设置 setSearchCount(false) 分页插件不会进行 count 查询
        // 要点!! 分页返回的对象与传入的对象是同一个
        IPage<JobInfo> pageResult = jobInfoMapper.getJobInfoList(page,jobSearchDto);
        Map<String,Object> result = new HashMap<String,Object>();
        List<JobInfo> records = pageResult.getRecords();
        TransformJobStatus(records);
        result.put("list", records);
        result.put("total",pageResult.getTotal());
        return result;
    }

    /**
     * 修改任务cron表达式
     * @param addJobDto
     * @throws Exception
     */
    public void updateJob(AddJobDto addJobDto) throws Exception {

        String triggerName = addJobDto.getTriggerName();
        String triggerGroupName = addJobDto.getTriggerGroupName();
        String jobClassName = addJobDto.getJobName();
        String jobGroupName = addJobDto.getJobGroupName();
        String cronExpression = addJobDto.getCronExpression();

        TriggerKey triggerKey =null;

        if(StringUtils.hasText(triggerName)||StringUtils.hasText(triggerGroupName)){
            triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
        }else {
            //通过任务名称和任务主修改
            List<? extends Trigger>triggers= scheduler.getTriggersOfJob(JobKey.jobKey(jobClassName,jobGroupName));
            if(triggers!=null&&triggers.size()>0){
                triggerKey=triggers.get(0).getKey();
            }
        }
        // 暂停任务.修改任务需要先暂停任务，否则可能会出现无法修改的情况（修改后瞬间恢复原值）
        scheduler.pauseTrigger(triggerKey);
        CronTrigger cronTrigger= (CronTrigger) scheduler.getTrigger(triggerKey);
        if(cronTrigger==null){
            System.out.println("定时任务出发时间为空！更新失败");
        }
        String oldTime=cronTrigger.getCronExpression();
        if(!oldTime.equals(cronExpression)){//判断表达式是否一致，如果一致则不需要修改
            TriggerBuilder<Trigger> triggerBuilder=TriggerBuilder.newTrigger();
            triggerBuilder.withIdentity(triggerKey.getName(),triggerKey.getGroup());
            triggerBuilder.startNow();
            //触发器设定
            triggerBuilder.withSchedule(
                    CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing());
            // 创建Trigger对象
            cronTrigger = (CronTrigger) triggerBuilder.build();
            scheduler.resumeTrigger(triggerKey);
            scheduler.rescheduleJob(triggerKey,cronTrigger);
        }
    }

    @Override
    public void pauseJob(JobOpertationDto jobOpertationDto) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(jobOpertationDto.getJobName(), jobOpertationDto.getJobGroupName()));
    }

    @Override
    public void resumeJob(JobOpertationDto jobOpertationDto) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(jobOpertationDto.getJobName(), jobOpertationDto.getJobGroupName()));
    }

    @Override
    public void deleteJob(JobOpertationDto jobOpertationDto) throws SchedulerException {
        String jobClassName = jobOpertationDto.getJobClassName();
        String jobGroupName = jobOpertationDto.getJobGroupName();
        // 停止触发器
        scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
        // 移除触发器
        scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
        // 移除任务
        scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
    }


    /**
     * 立即出发某个任务的执行
     * @param dto
     */
    @Override
    public void tiggerJob(JobOpertationDto dto) {
        try {
            JobKey key = new JobKey(dto.getJobName(),dto.getJobGroupName());
            scheduler.triggerJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void TransformJobStatus(List<JobInfo> list){
        list.forEach(item->{
            switch (item.getTriggerState()){
                case "PAUSED":
                    item.setTriggerState("暂停中");
                    break;
                case "ACQUIRED":
                    item.setTriggerState("运行中");
                    break;
            }
        });
    }



    public static BaseJob getClass(String classname) throws Exception {
        Class<?> clazz = Class.forName(classname);
        return (BaseJob) clazz.newInstance();
    }

    /**
     * 判断类是否存在
     * @param className
     * @return
     */
    private static Map<String,Object> verifyClass(String className){
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("resultMap",true);
        try {
            Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
            Class<?>[] interfaces = clazz.getInterfaces();
            for (Class<?> anInterface : interfaces) {
                if (BaseJob.class.getName().equals(anInterface.getName())){
                    resultMap.put("resultMap",false);
                    resultMap.put("message","添加的任务类需要基础基类：BaseJob");
                }
            }
        } catch (ClassNotFoundException e) {
            resultMap.put("resultMap",false);
            resultMap.put("message","添加的类不存在");
        }
        return resultMap;
    }


}
